package com.newlandedu.antchainvote.antchain.service;

import com.alipay.mychain.sdk.api.MychainClient;
import com.alipay.mychain.sdk.api.utils.Utils;
import com.alipay.mychain.sdk.common.VMTypeEnum;
import com.alipay.mychain.sdk.domain.account.Identity;
import com.alipay.mychain.sdk.errorcode.ErrorCode;
import com.alipay.mychain.sdk.message.transaction.TransactionReceiptResponse;
import com.alipay.mychain.sdk.message.transaction.contract.CallContractRequest;
import com.alipay.mychain.sdk.message.transaction.contract.DeployContractRequest;
import com.alipay.mychain.sdk.utils.ByteUtils;
import com.alipay.mychain.sdk.vm.EVMOutput;
import com.alipay.mychain.sdk.vm.EVMParameter;
import com.newlandedu.antchainvote.antchain.config.AntChainConfig;
import com.newlandedu.antchainvote.core.domain.AjaxResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.math.BigInteger;

/**
 * 用途
 *
 * @author deng
 * @date 2020/11/13 9:56
 */
@Service
public class AntChainServiceImpl implements AntChainService {
    private final Logger log = LoggerFactory.getLogger(this.getClass());
    private MychainClient sdk;
    private Identity userIdentity;

    public AntChainServiceImpl(AntChainConfig antChainConfig) {

        this.sdk = antChainConfig.sdk;
        this.userIdentity = antChainConfig.userIdentity;

    }

    @Override
    public AjaxResult deployContract(String contractId, String contractContent, EVMParameter contractParameters) {

        // build DeployContractRequest
        DeployContractRequest request = new DeployContractRequest(userIdentity,
                Utils.getIdentityByName(contractId), ByteUtils.hexStringToBytes(contractContent), VMTypeEnum.EVM,
                contractParameters, BigInteger.ZERO);

        //  set Gas limit
        // Make sure your account balance is greater than 50,000
        //request.setTxGas(50000);

        TransactionReceiptResponse deployContractResult;

        deployContractResult = sdk.getContractService().deployContract(request);
        // deploy contract
        if (!deployContractResult.isSuccess()
                || deployContractResult.getTransactionReceipt().getResult() != 0) {
            log.error("部署合约{},失败,{}",contractId,getErrorMsg((int) deployContractResult.getTransactionReceipt().getResult()));
            return AjaxResult.error("deployContract",
                    getErrorMsg((int) deployContractResult.getTransactionReceipt().getResult()));

        }
        log.info("部署{}合约成功",contractId);
        return AjaxResult.success();
    }

    @Override
    public AjaxResult callContract(String contractId, EVMParameter parameters) {

        // build CallContractRequest
        CallContractRequest request = new CallContractRequest(userIdentity,
                Utils.getIdentityByName(contractId), parameters, BigInteger.ZERO, VMTypeEnum.EVM);

        //  set Gas limit
        // Make sure your account balance is greater than 50,000
        //request.setTxGas(50000);

        TransactionReceiptResponse callContractResult;

        callContractResult = sdk.getContractService().callContract(request);


        if (!callContractResult.isSuccess() || callContractResult.getTransactionReceipt().getResult() != 0) {
            return AjaxResult.error(getErrorMsg((int) callContractResult.getTransactionReceipt().getResult()));
        }
        return AjaxResult.success();
    }

    @Override
    public AjaxResult queryContract(String contractId, EVMParameter parameters) {

        // build CallContractRequest
        CallContractRequest request = new CallContractRequest(userIdentity,
                Utils.getIdentityByName(contractId), parameters, BigInteger.ZERO, VMTypeEnum.EVM);

        //  set Gas limit
        // Make sure your account balance is greater than 50,000
        //request.setTxGas(50000);

        TransactionReceiptResponse callContractResult;

        callContractResult = sdk.getContractService().callContract(request);


        if (!callContractResult.isSuccess() || callContractResult.getTransactionReceipt().getResult() != 0) {
            return AjaxResult.error(getErrorMsg((int) callContractResult.getTransactionReceipt().getResult()));
        }
        byte[] output = callContractResult.getTransactionReceipt().getOutput();
        EVMOutput contractReturnValues = new EVMOutput(ByteUtils.toHexString(output));
        return AjaxResult.success(contractReturnValues);
    }


    private static String getErrorMsg(int errorCode) {
        int minMychainSdkErrorCode = ErrorCode.SDK_INTERNAL_ERROR.getErrorCode();
        if (errorCode < minMychainSdkErrorCode) {
            return ErrorCode.valueOf(errorCode).getErrorDesc();
        } else {
            return ErrorCode.valueOf(errorCode).getErrorDesc();
        }
    }
}
